#!/usr/bin/python
# -*- coding: UTF-8 -*-
########################################################
#             Copyright Infomation                     #
#         Powered by YIBANFU @ 2013~2014               #
#               http://yibanfu.com                     #
#               QQ Group:162616448                     #
########################################################

#>>>>>---------Customized variables begin----------<<<<<
CONFIG_USERID          = 'test@yibanfu.com'  # registered account on yibanfu.com
CONFIG_CLIENTUID       = '9527'              # customized id for different hosts
CONFIG_CIPHERKEY       = '0264ed0cb922792f'  # 16 or 32 chars. keep the same with the key in server
CONFIG_HTTPTIMEOUT     = 30                  # HTTP connection timeout in seconds
#>>>>>---------Customized variables end-------------<<<<<


























#!!!!!!!!!!!!!!!!!!!! Don't modify any lines below this !!!!!!!!!!!!!!!!!

CONFIG_CLIENTTYPE      = 'LINUX/AES'
CONFIG_RELEASE_VERSION = '1.0'
CONFIG_DEBUG_VERSION   = '0.0.6'
CONFIG_SERVERURL       = 'https://api.yibanfu.com/'
CONFIG_APPSECKEY       = '12222222222222112'             # reserved

''' ----------------  Commands used in this script ----------------
hostname -s
uname -asnrvmpio
cat /etc/issue.net | head -n 1
cat /etc/issue     | head -n 1
cat /proc/meminfo|head -n 5|awk '{print $2}'
cat /proc/cpuinfo
cat /proc/uptime
top -b -n 1
df -P | awk 'NR>1'
ps -ef | wc -l
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
netstat -tnpl | awk 'NR>2 {printf "%-6s %-30s %-30s\n",$1, $4,$7}'
/sbin/ip -o link|grep 'link/ether'|grep -v 'DOWN'
ps -eo rss,pmem,pcpu,vsize,args | awk 'NR>1 {print $0}' | sort -k 3 -r -n | head -n 10
ps -eo rss,pmem,pcpu,vsize,args | awk 'NR>1 {print $0}' | sort -k 4 -r -n | head -n 10
'''





import os
import sys
import time
import base64
import binascii
import urllib, urllib2
import commands
try:
    import cPickle as MyPickle
except ImportError:
    import pickle  as MyPickle
import socket
socket.setdefaulttimeout(CONFIG_HTTPTIMEOUT)

reload(sys)
sys.setdefaultencoding("utf-8")
os.putenv('LANGUAGE', 'en_US:en')
#os.putenv('TERM', 'xterm')

def AES_Func(sourceText, cipherKey, action = 'e'):
    '''
    AES encrypt and decrypt function by using action 'e' or 'd'
    '''
    try:
        from Crypto.Cipher import AES
        BLOCK_SIZE  = 32
        PADDING     = '~'
        pad         = lambda s: s + (BLOCK_SIZE - len(s) % BLOCK_SIZE) * PADDING
        EncodeAES   = lambda c, s: base64.b64encode(c.encrypt(pad(s)))
        DecodeAES   = lambda c, e: c.decrypt(base64.b64decode(e)).rstrip(PADDING)
        cipher      = AES.new(cipherKey)

        if action  == 'e':return EncodeAES(cipher, sourceText)
        if action  == 'd':return DecodeAES(cipher, sourceText)
    except ImportError:
        return sourceText

def getExecResult(cmdStr):
    status, result  = commands.getstatusoutput(cmdStr)
    if not       0 == status:return ''
    return result

def getHTTPPost(targetUrl, postData):
    r       = ''
    request = urllib2.Request(CONFIG_SERVERURL, data=postData)
    try:
        try:
            f   = urllib2.urlopen(request)
            r   = f.read()
        except Exception, e:
            print e
    finally:
        pass
    return r

def handleHTTPResult(result):
    print result

def doMainJob():
    SECINFO                      = AES_Func(SYSINFO.generateInfo(), CONFIG_CIPHERKEY, 'e')
    if ''                       == SECINFO:
        print 'AES_Func failed'
        return
    if                  SECINFO == SYSINFO:
        CRYPTOTYPE = 'NONE'
    else:
        CRYPTOTYPE = 'AES'
    postData                     = {}
    postData['CLIENTTYPE']       = CONFIG_CLIENTTYPE
    postData['CLIENTUID']        = CONFIG_CLIENTUID
    #postData['CIPHERKEY']        = CONFIG_CIPHERKEY
    postData['VERSION']          = CONFIG_RELEASE_VERSION
    postData['CONFIG_USERID']    = CONFIG_USERID
    postData['CONFIG_APPSECKEY'] = CONFIG_APPSECKEY
    postData['CRYPTOTYPE']       = CRYPTOTYPE
    postData['SYSINFO']          = SECINFO
    result                       = getHTTPPost(CONFIG_SERVERURL, urllib.urlencode(postData))
    handleHTTPResult(result)

class SYSINFO:
    '''
    get system info by executing shell scripts
    '''
    @staticmethod
    def generateInfo():
        info                        = {}
        info['hostname']            = SYSINFO.getHostName()
        info['issue']               = SYSINFO.getIssue()
        info['uname']               = SYSINFO.getUname()
        info['memory']              = SYSINFO.getMemory()
        info['memorytopn']          = SYSINFO.getMemoryTopN()
        info['cpu']                 = SYSINFO.getProcessor()
        info['cpuusage']            = SYSINFO.getCPUUsage()
        info['cputopn']             = SYSINFO.getCPUTopN()
        info['disk']                = SYSINFO.getDisk()
        info['uptime']              = SYSINFO.getUptime()
        info['processescount']      = SYSINFO.getProcessesCount()
        info['networkconnections']  = SYSINFO.getNetworkConnections()
        info['networklistening']    = SYSINFO.getNetworkListening()
        info['activemac']           = SYSINFO.getActiveMAC()
        info['unused']              = 'unused'
        try:
            return MyPickle.dumps(info, 2)
        except:
            try:
                return MyPickle.dumps(info, 1)
            except:
                try:
                    return MyPickle.dumps(info, 0)
                except:
                    return ''


    @staticmethod
    def getHostName():
        hostname = 'NONE'
        hostname = getExecResult('hostname -s')
        return {'hostname' : hostname}

    @staticmethod
    def getIssue():
        issue = 'NONE'
        if os.path.exists('/etc/issue.net'):
            issue = getExecResult('cat /etc/issue.net | head -n 1').replace('\\n', '').replace('\\l', '').strip()
        elif os.path.exists('/etc/issue'):
            issue = getExecResult('cat /etc/issue     | head -n 1').replace('\\n', '').replace('\\l', '').strip()
        else:
            issue = getExecResult('uname -n')
        return {'issue' : issue}

    @staticmethod
    def getUname():
        unameDict                            = { 'kernel_name'      : 'NONE', 'kernel_release'        : 'NONE' ,
                                                 'kernel_version'   : 'NONE', 'machine_hardware_name' : 'NONE' ,
                                                 'processor_type'   : 'NONE', 'hardware_platform'     : 'NONE' ,
                                                 'operating_system' : 'NONE' , 'network_node_hostname' : 'NONE' ,
                                                 'uname_all'        : 'NONE'  }
        unameDict['kernel_name']             = getExecResult('uname -s')
        unameDict['kernel_release']          = getExecResult('uname -r')
        unameDict['kernel_version']          = getExecResult('uname -v')
        unameDict['machine_hardware_name']   = getExecResult('uname -m')
        unameDict['processor_type']          = getExecResult('uname -p')
        unameDict['hardware_platform']       = getExecResult('uname -i')
        unameDict['operating_system']        = getExecResult('uname -o')
        unameDict['network_node_hostname']   = getExecResult('uname -n')
        unameDict['uname_all']               = getExecResult('uname -a')
        return unameDict
        
    @staticmethod
    def getMemory():
        memDict                   = { 'MemTotal' : '0', 'MemFree' : '0', 'Buffers' : '0', 'Cached' : '0', 'SwapCached' : '0'}
        cmdStr                    = "cat /proc/meminfo|head -n 5|awk '{print $2}'"
        memList                   = getExecResult(cmdStr).splitlines()
        if     len(memList)      == 5:
            memDict['MemTotal']   = memList[0]
            memDict['MemFree']    = memList[1]
            memDict['Buffers']    = memList[2]
            memDict['Cached']     = memList[3]
            memDict['SwapCached'] = memList[4]
        return memDict
    
    @staticmethod
    def getProcessor():
        return SYSINFO.getCPU()

    @staticmethod
    def getCPU():
        cpuDict          = {'0' : { 'vendorid' : 'NONE', 'modelname'   : 'NONE', 
                                    'cpuMHZ'   : '0'   , 'cachesizeKB' : '0'   , 
                                    'siblings' : '0'   , 'cpucores'    : '0'     }}
        cpuCount         = getExecResult('cat /proc/cpuinfo | grep processor | wc -l')
        if '' == cpuCount or 0 == int(cpuCount) : return cpuDict
        cpuCount         = int(cpuCount)
        vendorid_List    = getExecResult("cat /proc/cpuinfo | grep vendor_id    | awk        '{print $3}'").splitlines()
        modelname_List   = getExecResult("cat /proc/cpuinfo | grep 'model name' | awk -F': ' '{print $2}'").splitlines()
        cpuMHZ_List      = getExecResult("cat /proc/cpuinfo | grep MHz          | awk        '{print $4}'").splitlines()
        cachesizeKB_List = getExecResult("cat /proc/cpuinfo | grep 'cache size' | awk        '{print $4}'").splitlines()
        siblings_List    = getExecResult("cat /proc/cpuinfo | grep siblings     | awk        '{print $3}'").splitlines()
        cpucores_List    = getExecResult("cat /proc/cpuinfo | grep 'cpu cores'  | awk        '{print $4}'").splitlines()
        if not len(vendorid_List)   == cpuCount or \
           not len(modelname_List)  == cpuCount or \
           not len(cpuMHZ_List)     == cpuCount or \
           not len(cachesizeKB_List)== cpuCount:return cpuDict
        for i in range(cpuCount):
            tempDict                 =  { 'vendorid' : 'NONE', 'modelname'   : 'NONE', 
                                          'cpuMHZ'   : '0'   , 'cachesizeKB' : '0'   , 
                                          'siblings' : '0'   , 'cpucores'    : '0'     }
            tempDict['vendorid']     = vendorid_List[i]
            tempDict['modelname']    = modelname_List[i]
            tempDict['cpuMHZ']       = cpuMHZ_List[i]
            tempDict['cachesizeKB']  = cachesizeKB_List[i]
            if len(siblings_List)   == cpuCount:
                tempDict['siblings'] = siblings_List[i]
            if len(cpucores_List)   == cpuCount:
                tempDict['cpucores'] = cpucores_List[i]
            cpuDict['%d' % i]        = tempDict
        return cpuDict

    @staticmethod
    def getCPUUsage():
        cmdStr             = "top -b -n 1 | grep -v grep |grep 'Cpu(s):'"
        cpuusageStr        = getExecResult(cmdStr)
        cpuusageDict       = { 'us' : '0', 'sy' : '0', 'ni' : '0', 'id' : '100',
                               'wa' : '0', 'hi' : '0', 'si' : '0', 'st' : '0'   }
        #Cpu(s):  0.7%us,  1.0%sy,  0.2%ni, 97.0%id,  1.1%wa,  0.0%hi,  0.0%si,  0.0%st
        if not len(cpuusageStr.split(',')) == 8 : return cpuusageDict
        cpuusageDict['us'] = cpuusageStr.split('%us')[0].split(':')[-1].strip()
        cpuusageDict['sy'] = cpuusageStr.split('%sy')[0].split(',')[-1].strip()
        cpuusageDict['ni'] = cpuusageStr.split('%ni')[0].split(',')[-1].strip()
        cpuusageDict['id'] = cpuusageStr.split('%id')[0].split(',')[-1].strip()
        cpuusageDict['wa'] = cpuusageStr.split('%wa')[0].split(',')[-1].strip()
        cpuusageDict['hi'] = cpuusageStr.split('%hi')[0].split(',')[-1].strip()
        cpuusageDict['si'] = cpuusageStr.split('%si')[0].split(',')[-1].strip()
        cpuusageDict['st'] = cpuusageStr.split('%st')[0].split(',')[-1].strip()
        return cpuusageDict

    @staticmethod
    def getDisk():
        diskStr  = getExecResult("df -P | awk 'NR>1 {print $0}'")
        diskList = diskStr.splitlines()
        diskDict = { '0' : { 'filesystem' : 'NONE', 'mountname' : 'NONE',
                             'totalsize'  : '0'   , 'usedsize'  : '0'   ,
                             'unusedsize' : '100' , 'usedrate'  : '0'    }}
        for i in range(len(diskList)):
            item                   = diskList[i]
            itemSplited            = item.split()
            if not 6              == len(itemSplited) : continue
            tempDict               = { 'filesystem' : 'NONE', 'mountname' : 'NONE',
                                       'totalsize'  : '0'   , 'usedsize'  : '0'   ,
                                       'usedrate'   : '100' , 'mountname' : '0'    }
            tempDict['filesystem'] = itemSplited[0]
            tempDict['totalsize']  = itemSplited[1]
            tempDict['usedsize']   = itemSplited[2]
            tempDict['unusedsize'] = itemSplited[3]
            tempDict['usedrate']   = itemSplited[4][0:-1]
            tempDict['mountname']  = itemSplited[5]
            diskDict['%d' % i]     = tempDict
        return diskDict

    @staticmethod
    def getUptime():
        uptime = '0'
        uptime = getExecResult("cat /proc/uptime | awk '{print $1}' ")
        return {'uptime' : uptime}

    @staticmethod
    def getProcessesCount():
        processesCount = '0'
        processesCount = getExecResult("ps -ef| grep -v 'ps -ef' | wc -l")
        return {'processesCount' : processesCount}
        
    @staticmethod
    def getNetworkConnections():
        cmdStr      = "netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'"
        statusStr   = getExecResult(cmdStr)
        statusList  = statusStr.splitlines()
        statusDict  = { '0' : { 'statusname' : 'NONE', 'statuscount' : '0' }}
        for i in range(len(statusList)):
            item                      = statusList[i]
            if not len(item.split()) == 2 : continue
            tempDict                  = { 'statusname' : 'NONE', 'statuscount' : '0' }
            tempDict['statusname']    = item.split()[0]
            tempDict['statuscount']   = item.split()[1]
            statusDict["%s" % i]      = tempDict
        return statusDict

    @staticmethod
    def getNetworkListening():
        listeningDict = { '0' : { 'protocol' : 'NONE', 'port' : '0', 'ip' : '127.0.0.1',
                                  'process'  : 'NONE', 'pid'  : '0' }}
        cmdStr        = 'netstat -tnpl > /tmp/yibanfu.netstat.tmp'
        getExecResult(cmdStr)
        if not os.path.exists('/tmp/yibanfu.netstat.tmp'):return listeningDict
        
        cmdStr        = "cat /tmp/yibanfu.netstat.tmp | awk 'NR>2 {printf \"%-6s %-30s %-30s\\n\",$1, $4,$7}'"
        listeningList =  getExecResult(cmdStr).splitlines()
        
        for i in range(len(listeningList)):
            item                     = listeningList[i]
            itemSplited              = item.split()
            if -1 == item.find(':') or not len(itemSplited) ==  3 : continue
            tempDict                 = { 'protocol' : 'NONE', 'port' : '0', 'ip' : '127.0.0.1',
                                         'process'  : 'NONE', 'pid'  : '0'}
            tempDict['protocol']     = itemSplited[0]
            tempDict['port']         = itemSplited[1].split(':')[-1]
            tempDict['ip']           = itemSplited[1].replace(':' + tempDict['port'], '')
            tempDict['pid']          = itemSplited[-1].split('/')[0]
            tempDict['process']      = itemSplited[-1].split('/')[-1]
            listeningDict['%d' % i]  = tempDict

        getExecResult('rm -rf /tmp/yibanfu.netstat.tmp')
        return listeningDict

    @staticmethod
    def getMemoryTopN(top = 5):
        memTopNDict       = { '0' : { 'pid'  : '0', 'rss'   : '0', 'pmem' : '0',
                                    'pcpu' : '0', 'vsize' : '0', 'args' :'NONE' }}
        cmdStr            = "ps -eo pid,rss,pmem,pcpu,vsize,args | grep -v 'ps -eo pid,rss,pmem,pcpu,vsize,args' | grep -v 'NR>1 {print          $0}' | grep -v 'sort -k 3 -r -n' | awk 'NR>1 {print          $0}' | sort -k 3 -r -n > /tmp/yibanfu.memTopN.tmp"
        getExecResult(cmdStr)
        if not os.path.exists('/tmp/yibanfu.memTopN.tmp'):return memTopNDict
        
        cmdStr            = 'cat /tmp/yibanfu.memTopN.tmp |head -n 10 | cut -c1-160'
        memTopNList       = getExecResult(cmdStr).splitlines()
        
        for i in range(len(memTopNList)):
            item                          = memTopNList[i]
            itemSplit                     = item.split()
            if  not   len(itemSplit)      > 5 : continue

            tempDict                      = { 'pid'  : '0', 'rss'   : '0', 'pmem' : '0',
                                              'pcpu' : '0', 'vsize' : '0', 'args' :'NONE' }
            (pid, rss, pmem, pcpu, vsize) = (itemSplit[0], itemSplit[1], itemSplit[2], itemSplit[3], itemSplit[4])
            args                          = item.split(' %s ' % vsize)[-1]

            tempDict['pid']               = pid
            tempDict['rss']               = rss
            tempDict['pmem']              = pmem
            tempDict['pcpu']              = pcpu
            tempDict['vsize']             = vsize
            tempDict['args']              = args
            memTopNDict["%d" % i]         = tempDict
        
        getExecResult('rm -rf /tmp/yibanfu.memTopN.tmp')
        return memTopNDict

    @staticmethod
    def getCPUTopN(top = 5):
        cpuTopNDict    = { '0' : { 'pid'  : '0', 'rss'   : '0', 'pmem' : '0',
                                    'pcpu' : '0', 'vsize' : '0', 'args' :'NONE' }}
        cmdStr         = "ps -eo pid,rss,pmem,pcpu,vsize,args | grep -v 'ps -eo pid,rss,pmem,pcpu,vsize,args' | grep -v 'NR>1 {print          $0}' | grep -v 'sort -k 4 -r -n' | awk 'NR>1 {print          $0}' | sort -k 4 -r -n > /tmp/yibanfu.CPUTopN.tmp"
        getExecResult(cmdStr)
        if not os.path.exists('/tmp/yibanfu.CPUTopN.tmp') : return cpuTopNDict
        
        cmdStr         = 'cat /tmp/yibanfu.CPUTopN.tmp | head -n 10 | cut -c1-160'
        cpuTopNList    = getExecResult(cmdStr).splitlines()
        
        for i in range(len(cpuTopNList)):
            item                          = cpuTopNList[i]
            itemSplit                     = item.split()
            if  not   len(itemSplit)      > 5 : continue

            tempDict                      = { 'pid'  : '0', 'rss'   : '0', 'pmem' : '0',
                                              'pcpu' : '0', 'vsize' : '0', 'args' :'NONE' }
            (pid, rss, pmem, pcpu, vsize) = (itemSplit[0], itemSplit[1], itemSplit[2], itemSplit[3], itemSplit[4])
            args                          = item.split(' %s ' % vsize)[-1]

            tempDict['pid']               = pid
            tempDict['rss']               = rss
            tempDict['pmem']              = pmem
            tempDict['pcpu']              = pcpu
            tempDict['vsize']             = vsize
            tempDict['args']              = args
            cpuTopNDict["%d" % i]         = tempDict
        
        getExecResult('rm -rf /tmp/yibanfu.CPUTopN.tmp')
        return cpuTopNDict

    @staticmethod
    def getActiveMAC():
        if not os.path.exists('/sbin/ip'):
            cmdStr      = "ip       -f inet -o link | sort | grep 'link/ether' | grep -v 'DOWN'"
        else:
            cmdStr      = "/sbin/ip -f inet -o link | sort | grep 'link/ether' | grep -v 'DOWN'"
        activeMACList   = getExecResult(cmdStr).splitlines()
        activeMACDict   = { '0' : { 'ethname' : 'NONE', 'ethmac' : 'NONE'}}
        for i in range(len(activeMACList)):
            item                    = activeMACList[i]
            tempDict                = { 'ethname' : 'NONE', 'ethmac' : 'NONE'}
            tempDict['ethname']     = item.split(': ')[1]
            tempDict['ethmac']      = item.split('link/ether')[-1].split('brd')[0].strip().upper()
            activeMACDict["%d" % i] = tempDict
        return activeMACDict

def showHelp():
    print '''
+-------------------------------------------------+
|       Welcome to use YIBANFU software           |
|            http://yibanfu.com                   |
|            QQ Group:162616448                   |
+-------------------------------------------------+

To add crontab, please execute "crontab -e" and 
  set your schedule, for example:
*/5 * * * * /root/.py >> /tmp/ybf.log

To list crontab, please execute "crontab -l"
'''

if __name__ == '__main__':
    print "### YIBANFU CLIENT: %s" % time.strftime('%Y:%m:%d %H-%M-%S')
    if os.name == 'nt' or not os.name == 'posix':
        print 'OS platform is not supported by this verison of script...'
        sys.exit()
    if not len(sys.argv) > 1:
        '''
        print SYSINFO.getMemory()
        print SYSINFO.getIssue()
        print SYSINFO.getHostName()
        print SYSINFO.getUname()
        print SYSINFO.getUptime()
        print SYSINFO.getNetworkConnections()
        print SYSINFO.getNetworkListening()
        print SYSINFO.getCPU()
        print SYSINFO.getDisk()
        print SYSINFO.getCPUUsage()
        print SYSINFO.getCPUTopN(10)
        print SYSINFO.getMemoryTopN(10)
        '''
        #print SYSINFO.getActiveMAC()
        doMainJob()
    else:
        showHelp()